#include "Socket.hpp"
#include <pthread.h>
#include <vector>
#include <sstream>
#include <fstream>
static const int defaultport = 8080;

const std::string sep = "\r\n";
const std::string wwwroot = "./wwwroot"; // web 根目录
class HttpServer;
// 用于给线程函数传参
class ThreadData
{
public:
    ThreadData(int sockfd, HttpServer *svr) : sockfd_(sockfd), svr_(svr)
    {
    }

public:
    int sockfd_;
    HttpServer *svr_;
};

class HttpRequest
{
public:
    void Deserialize(std::string req)
    {
        while (true)
        {
            std::size_t pos = req.find(sep); // 将每一行的信息都插入到vector中
            if (pos == std::string::npos)
                break;
            std::string tmp = req.substr(0, pos);
            if (tmp.empty())
                break;
            req_header.push_back(tmp);
            req.erase(0, pos + sep.size()); // 一行中也有 '\r\n' ，所以需要加上这个长度
        }
    }

    // 解析请求行
    void Parse()
    {
        std::stringstream ss(req_header[0]);
        ss >> method >> url >> http_version;
        file_path = wwwroot; // 所有的文件都在 wwwroot中
        if (url == "/" || url == "/index.html")
        {
            // 当用户不指明访问路径的时候，给用户默认访问./wwwroot/index.html
            file_path += "/index.html";
        }
        else
        {
            file_path += url;
        }
    }

public:
    std::vector<std::string> req_header; // 将用户发送的报文放进到vector中

    std::string method;       // 请求方法
    std::string url;          // 路径
    std::string http_version; // http版本
    std::string file_path;    // http服务器所有的访问路径
};
class HttpServer
{
public:
    HttpServer(uint16_t port = defaultport)
        : port_(port)
    {
    }

    void start()
    {
        listensock_.Socket();
        listensock_.Bind(port_);
        listensock_.Listen();

        while (1)
        {
            // 建立连接
            std::string clientip;
            uint16_t clientport;
            int socketfd = listensock_.Accept(&clientip, &clientport);
            if (socketfd < 0)
            { // 重新连接
                continue;
            }
            lg(Info, "get a new connect, sockfd: %d", socketfd);
            // 建立连接成功后，对用户发来的请求做处理
            // 创建线程来处理
            pthread_t tid;
            ThreadData *td = new ThreadData(socketfd, this);
            pthread_create(&tid, nullptr, ThreadRun, td);
        }
    }

    // 线程处理用户请求
    static void *ThreadRun(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(args);

        // 处理细节另设函数
        td->svr_->HandlerHttp(td->sockfd_);
        delete td;
        return nullptr;
    }

    // 处理细节
    static void HandlerHttp(int sockfd)
    {
        // 接受信息recv,向用户发送信息send
        char buffer[10240];
        ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0; // 当作字符串来读取
            std::cout << buffer << std::endl;

            HttpRequest res;
            // 反序列化
            res.Deserialize(buffer);
            res.Parse();

            // 处理用户请求的内容
            std::string text;
            bool path_right = true;
            text = HandlerContent(res.file_path);
            if (text.empty())   //如果用户访问路径根本不存在，则返回一个错误界面
            {
                path_right = false;
                std::string err_html = wwwroot;
                err_html += "/";
                err_html += "err.html";
                text = HandlerContent(err_html);
            }

            std::string response_line;   //res首行 ，状态行
            if (path_right)
                response_line = "HTTP/1.0 200 OK\r\n";
            else
                response_line = "HTTP/1.0 404 Not Found\r\n";

            std::string response_header = "Content-Length: ";    //相应报文
            response_header += std::to_string(text.size()); // Content-Length: 11
            response_header += "\r\n";
            response_header += "Set-Cookie: username=R_L&&passwd=123";
            response_header += "\r\n";
            std::string blank_line = "\r\n"; //空白行
            // 将得到的结果返回给用户

            std::string response = response_line;
            response += response_header;
            response += blank_line;
            response += text;

            send(sockfd, response.c_str(), response.size(), 0);
            // respond
        }

        // 处理完后关掉sockfd
        close(sockfd);
    }

    //  处理用户请求的内容
    static std::string HandlerContent(std::string htmlpath)
    {
        // 以二进制的方式读数据
        std::ifstream in(htmlpath, std::ios::binary);
        if (!in.is_open())
            return "";

        in.seekg(0, std::ios_base::end);
        auto len = in.tellg();
        in.seekg(0, std::ios_base::beg);

        std::string content;
        content.resize(len);

        in.read((char *)content.c_str(), content.size());
        // std::string content;
        // std::string line;
        // while(std::getline(in, line))
        //{
        //     content += line;
        // }

        in.close();

        return content;
    }

private:
    Sock listensock_; // 套接字相关接口
    uint16_t port_;   // 端口号
};